/*******************************************
Module: zt_str.c
E-Mail: 24zhutian@gmail.com
Notices: Copyright (c) 2007-2011 ls
*******************************************/
#include "zt_config.h"
#include "zt_str.h"

/* 
* converts hex char (0-9, A-Z, a-z) to decimal.
* returns 0xFF on invalid input.
*/
#define X2C(x,c) {c=(u_char)(x-'0');if(c>9){c=(u_char)((c+'0'-1)|0x20);c=(u_char)(c-'a'+11);}}

static const u_char _hex_char[] = "0123456789ABCDEF";
/* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
static const u_char _uri_char[] = {
	/*
	0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F
	*/
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
	1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,  /*  20 -  2F space " # $ % & ' + , / */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,  /*  30 -  3F : ; < = > ? */
	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
	1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  B0 -  BF */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  C0 -  CF */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  D0 -  DF */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  E0 -  EF */
	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  F0 -  FF */
};
static const u_char		_b64_char[]		= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const u_char		_unb64_char[]	= {
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
	52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
	77,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
	77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
		
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
	77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
};

ZT_API size_t zt_strlen(const u_char *str)
{
	const u_char *s;
	
	for(s=str;*s;++s);
	
	return(s-str);
}

ZT_API u_char* zt_tolower(u_char *str)
{
	u_char *c;
	
	for(c=str;*c;c++){
		if(*c>='A'&&*c<='Z'){
			*c|=32;
		}
	}
	
	return(str);
}

ZT_API u_char* zt_toupper(u_char *str)
{
	u_char *c;
	
	for(c=str;*c;c++){
		if(*c>='a'&&*c<='z'){
			*c&=~32;
		}
	}
	
	return(str);
}

ZT_API u_char* zt_strcpy(u_char *to,const u_char *from)
{
	u_char *save=to;
	
	for (; (*to = *from) != '\0'; ++from, ++to);
	
	return(save);
}

ZT_API u_char* zt_strncpy(u_char *to,const u_char *from,size_t n)
{
	if (n != 0) {
		u_char *d = to;
		const u_char *s = from;
		
		do {
			if ((*d++ = *s++) == 0) {
				/* NUL pad the remaining n-1 bytes */
				while (--n != 0)
					*d++ = 0;
				break;
			}
		} while (--n != 0);
	}
	return (to);
}

ZT_API u_char* zt_strcat(u_char *str,const u_char *append)
{
	u_char *save=str;

	for(;*str;++str);
	while((*str++=*append++)!='\0');

	return(save);
}

ZT_API u_char* zt_strncat(u_char *dst,const u_char *src,size_t siz)
{
	u_char *d=dst;
	const u_char *s=src;

	if(siz!=0){
		while(*d!=0){
			d++;
		}
		do{
			if((*d=*s++)==0){
				break;
			}
			d++;
		}while(--siz!=0);
		*d=0;
	}
	return(dst);
}

ZT_API int zt_strncmp(const u_char *s1, const u_char *s2, size_t n)
{
	if (n == 0)
		return (0);
	do {
		if (*s1 != *s2++){
			return (*s1 - *--s2);
		}
		if (*s1++ == 0){
			break;
		}
	} while (--n != 0);
	return (0);
}

ZT_API int zt_strcmp(const u_char *s1, const u_char *s2)
{
	while (*s1 == *s2++){
		if (*s1++ == 0){
			return (0);
		}
	}
	return (*s1 - *--s2);
}

ZT_API u_char* zt_strchr(const u_char *s,u_char c)
{
	const u_char *p=s;
	
	for(;;){
		if(*p==c){
			return((u_char *)p);
		}
		if(!*p){
			return(NULL);
		}
		p++;
	}
}

ZT_API u_char* zt_strstr(const u_char* src,u_char *dst)
{
	register u_char *cp=(u_char *)src;
	register u_char *s1, *s2;
	
	if (!*dst){
		return((u_char *)src);
	}

	while (*cp)
	{
		s1 = cp;
		s2 = (u_char *)dst;

		while (*s1&&*s2&&!(*s1-*s2)){
			s1++, s2++;
		}
		if (!*s2){
			return(cp);
		}
		cp++;
	}
	
    return(NULL);
}

ZT_API size_t zt_strchrcpy(u_char *dst,const u_char *s,u_char c)
{
	register u_char *cp=(u_char *)s;

	while(*cp){
		if(*cp==c){
			break;
		}
		if(!*cp){
			return(0);
		}
		*dst++=*cp;
		cp++;
	}
	return(cp-s);
}

ZT_API u_char* zt_strdup(u_char *str,size_t siz)
{
	u_char *cp;
	
	cp=(u_char *)malloc(siz+sizeof(u_char));
	if(cp){
		memcpy(cp,str,siz);
		*(cp+siz)='\0';
		return(cp);
	}
	return(NULL);
}

ZT_API int zt_strcasecmp(u_char *s1,u_char *s2)
{
	u_char c1,c2;

	for ( ;; ) {
        c1 = *s1++;
        c2 = *s2++;
		
        c1 = (u_char)((c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1);
        c2 = (u_char)((c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2);
		
        if (c1 == c2) {			
            if (c1) {
                continue;
            }			
            return (0);
        }		
        return (c1 - c2);
    }
}

ZT_API int zt_strncasecmp(u_char *s1,u_char *s2,size_t n)
{
	u_char c1,c2;

	while (n) {
        c1 = *s1++;
        c2 = *s2++;
		
        c1 = (u_char)((c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1);
        c2 = (u_char)((c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2);
		
        if (c1 == c2) {			
            if (c1) {
                n--;
                continue;
            }			
            return (0);
        }		
        return (c1 - c2);
    }
	
    return (0);
}

ZT_API size_t zt_uri_escape_siz(const u_char *str)
{
	register size_t siz=0;
	
	while(*str)
	{
		if(_uri_char[*str]){
			siz+=3;
		}
		else{
			siz++;
		}
		str++;
	}
	return(siz);
}

ZT_API size_t zt_uri_escape(u_char *dst,const u_char *src)
{
	u_char	*cp=dst;

	while(*src){
		if(_uri_char[*src]){
			*dst++='%';
			*dst++=_hex_char[(*src)>>4];
			*dst++=_hex_char[(*src)&0x0f];
			src++;		
		}
		else{
			*dst++=*src++;
		}
	}
	
	return(dst-cp);
}

ZT_API size_t zt_uri_unescape_siz(const u_char *str)
{
	register size_t siz=0;
	register unsigned char high, low;
	
	while(*str){
		if(*str=='%'){
			siz++;
			X2C(*(str+1),high);
			if(high<0x10){
				X2C(*(str+2),low);
				if(low<0x10){
					str+=2;
				}
			}
		}
		else{
			siz++;
		}
		str++;
	}
	
	return(siz);
}

ZT_API size_t zt_uri_unescape(u_char *dst,const u_char *src)
{
	register unsigned char high, low;
	u_char *cp=dst;
	
	while((*src)!= '\0'){
		if (*src=='%'){
			X2C(*(src+1),high);
			if(high<0x10){
				X2C(*(src+2),low);
				if (low<0x10) {
					high=(u_char)((high<<4)|low);
					*dst=high;
					src+=2;
				}
			}
		}
		else if (*src == '+') {
			*dst=' ';
		}
		else {
			*dst=*src;
		}		
		dst++;
		src++;
	}
	
	return(dst-cp);
}

ZT_API size_t zt_base64_escape(u_char *dst,const u_char *str,size_t siz)
{
	u_char         *d=dst, *s=(u_char *)str;
	
    while (siz>2) {
        *d++ = _b64_char[(s[0] >> 2) & 0x3f];
        *d++ = _b64_char[((s[0] & 3) << 4) | (s[1] >> 4)];
        *d++ = _b64_char[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
        *d++ = _b64_char[s[2] & 0x3f];
		
        s += 3;
        siz -= 3;
    }
	
    if (siz) {
        *d++ = _b64_char[(s[0] >> 2) & 0x3f];
        if(siz==1){
            *d++ = _b64_char[(s[0] & 3) << 4];
            *d++ = '=';
        }
		else{
            *d++ = _b64_char[((s[0] & 3) << 4) | (s[1] >> 4)];
            *d++ = _b64_char[(s[1] & 0x0f) << 2];
        }		
        *d++ = '=';
    }
	
    return(d-dst);
}

ZT_API size_t zt_base64_unescape(u_char *dst,const u_char *str,size_t siz)
{
	size_t          len;
    u_char         *d, *s;    
	
    for (len = 0; len < siz; len++) {
        if(str[len] == '='){
            break;
        }		
        if(_unb64_char[str[len]]== 77){
            return(0);
        }
    }
	
    if(len%4==1){
        return(0);
    }
	
    s = (u_char *)str;
    d = dst;
	
    while (len > 3) {
        *d++ = (u_char) (_unb64_char[s[0]] << 2 | _unb64_char[s[1]] >> 4);
        *d++ = (u_char) (_unb64_char[s[1]] << 4 | _unb64_char[s[2]] >> 2);
        *d++ = (u_char) (_unb64_char[s[2]] << 6 | _unb64_char[s[3]]);
		
        s += 4;
        len -= 4;
    }
	
    if (len > 1) {
        *d++ = (u_char)(_unb64_char[s[0]] << 2 | _unb64_char[s[1]]>> 4);
    }
	
    if (len > 2) {
        *d++ = (u_char)(_unb64_char[s[1]] << 4 | _unb64_char[s[2]] >> 2);
    }
	
    return(d-dst);
}

ZT_API size_t	zt_hex_escape(u_char *dst,const u_char *src)
{
	u_char	*cp=dst;
	
	while(*src){
		if(_uri_char[*src]){			
			*dst++=_hex_char[(*src)>>4];
			*dst++=_hex_char[(*src)&0x0f];
			src++;		
		}
		else{
			*dst++=*src++;
		}
	}
	
	return(dst-cp);
}

ZT_API size_t	zt_hex_unescape(u_char *dst,const u_char *src)
{
	register unsigned char high, low;
	u_char *cp=dst;
	
	while((*src)!= '\0'){
		X2C(*(src),high);
		if(high<0x10){
			X2C(*(src+1),low);
			if (low<0x10) {
				high=(u_char)((high<<4)|low);
				*dst=high;
				src+=2;
			}
		}
		else{
			*dst=*src;
			src++;
		}
		dst++;
	}
	
	return(dst-cp);
}

ZT_API zt_int_t zt_atoi(u_char *str, size_t n)
{
    zt_int_t  value;
	
    if (n == 0) {
        return (ZT_ERR);
    }
	
    for (value = 0; n--; str++) {
        if (*str < '0' || *str > '9') {
            return (ZT_ERR);
        }
		
        value = value * 10 + (*str - '0');
    }
	
    if (value < 0) {
        return (ZT_ERR);
		
    } else {
        return value;
    }
}

ZT_API size_t zt_cs_charset(u_char **dst,unsigned int cs,unsigned int tcs,u_char *src,size_t n,u_char *wbuf)
{
	size_t size=0,sizew=0;
#ifdef _MSC_VER	
	size=MultiByteToWideChar(tcs,0,(LPCTSTR)src,n,NULL,0);
	if(size>0){
		sizew=MultiByteToWideChar(tcs,0,(LPCTSTR)src,n,(LPWSTR)wbuf,size);
		size=WideCharToMultiByte(cs,0,(LPWSTR)wbuf,sizew,NULL,0,NULL,NULL);
		WideCharToMultiByte(cs,0,(LPWSTR)wbuf,sizew,(LPSTR)*dst,size,NULL,NULL);
	}
#endif
	return(size);
}

ZT_API zt_str_t* zt_str_alloc(size_t siz)
{
	zt_str_t *str=NULL;
	u_char *p=NULL;
	
	str=ZT_MEM_MALLOC(zt_str_t,1);
	if(str){
		p=ZT_MEM_MALLOC(u_char,(siz+1));
		if(!p){
			free(str);
			return(NULL);
		}
		str->siz=siz;
		str->str=p;
		str->use=0;
	}
	return(str);
}

ZT_API zt_int_t	zt_str_free(zt_str_t *str)
{
	if(str){
		if(str->siz>0){
			free(str->str);
		}		
		free(str);
		str=NULL;
	}
	return(ZT_OK);
}

ZT_API size_t zt_str_strcpy(zt_str_t *dst,u_char *src)
{
    u_char *save=dst->str;
	
    while((*save++=*src++)!='\0');
    dst->use=save-(dst->str+dst->use)-sizeof(u_char);
	
    return(dst->use);
}

ZT_API size_t zt_str_strcat(zt_str_t *dst,u_char *src)
{
    u_char *save=dst->str+dst->use;
	
    while((*save++=*src++)!='\0');
    dst->use+=save-(dst->str+dst->use)-sizeof(u_char);
	
    return(dst->use);
}

ZT_API int zt_str_find(zt_str_t *str,u_char *s)
{
	u_char *p;
	
	p=zt_strstr(str->str,s);
	
	return(p==NULL?-1:(p-str->str));
}

ZT_API int zt_str_substr(u_char *p,zt_str_t *str,size_t pos,int n)
{
	int siz=0;
	
	if(pos>=str->use){
		p=NULL;
	}
	else{
		if(n>0){
			if((pos+n)>str->use){
				siz=str->use-pos;
				ZT_MEMCPY(p,str->str+pos,siz);
			}
			else{
				siz=n;
				ZT_MEMCPY(p,str->str+pos,siz);
			}
		}
		else{
			if(n==0){
				siz=str->use-pos;
				ZT_MEMCPY(p,str->str+pos,siz);
			}
			else{
				siz=-n;
				if(pos>(size_t)siz){
					ZT_MEMCPY(p,str->str+(pos-siz),siz);
				}
				else{
					siz=pos;
					ZT_MEMCPY(p,str->str,pos);
				}
			}
		}
	}
	return(siz);
}
